package org.kiwi.util;

import lombok.Data;
import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;

import static org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE;

/**
 * ftp工具
 *
 * @email jack.liu.19910921@gmail.com
 * Created by jack on 17/7/6.
 */
public class FtpUtil {

    /**
     * 文件上传
     *
     * @param ftpConfig
     * @throws Exception
     */
    public static void upload(FtpConfig ftpConfig) throws Exception {
        uploadInternal(ftpConfig.getIp(),
                ftpConfig.getPort(),
                ftpConfig.getUserName(),
                ftpConfig.getPassword(),
                ftpConfig.getRemotePath(),
                ftpConfig.getRemoteName(),
                ftpConfig.getLocalPath(),
                ftpConfig.getLocalName());
    }

    /**
     * 文件下载
     *
     * @param ftpConfig
     * @throws Exception
     */
    public static void download(FtpConfig ftpConfig) throws Exception {
        downloadInternal(ftpConfig.getIp(),
                ftpConfig.getPort(),
                ftpConfig.getUserName(),
                ftpConfig.getPassword(),
                ftpConfig.getRemotePath(),
                ftpConfig.getRemoteName(),
                ftpConfig.getLocalPath(),
                ftpConfig.getLocalName());
    }


    /**
     * 上传
     *
     * @param ip
     * @param port
     * @param username
     * @param password
     * @param remotePath
     * @param remoteName
     * @param localPath
     * @param localName
     * @throws Exception
     */
    private static void uploadInternal(String ip,
                                       int port,
                                       String username,
                                       String password,
                                       String remotePath,
                                       String remoteName,
                                       String localPath,
                                       String localName) throws Exception {
        FTPClient ftpClient = null;

        try {
            ftpClient = loginAndChangeWorkingDirectory(ip, port, username, password, remotePath);

            InputStream inputStream = null;
            try {
                inputStream = new FileInputStream(new File(localPath + File.separator + localName));
                ftpClient.storeFile(remoteName, inputStream);
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
            }

        } finally {
            logout(ftpClient);
        }
    }

    /**
     * 下载
     *
     * @param ip
     * @param port
     * @param username
     * @param password
     * @param remotePath
     * @param remoteName
     * @param localPath
     * @param localName
     * @throws Exception
     */
    private static void downloadInternal(String ip,
                                         int port,
                                         String username,
                                         String password,
                                         String remotePath,
                                         String remoteName,
                                         String localPath,
                                         String localName) throws Exception {
        FTPClient ftpClient = null;

        try {
            ftpClient = loginAndChangeWorkingDirectory(ip, port, username, password, remotePath);

            ftpClient.enterLocalPassiveMode();// 告诉ftp server开通一个端口来传输数据

            FTPFile[] ftpFiles = ftpClient.listFiles();
            for (FTPFile ftpFile : ftpFiles) {
                if (ftpFile.getName().equals(remoteName)) {

                    OutputStream outputStream = null;
                    try {
                        outputStream = new FileOutputStream(new File(localPath + File.separator + localName));
                        InputStream inputStream = ftpClient.retrieveFileStream(ftpFile.getName());
                        IOUtils.copy(inputStream, outputStream);
                        outputStream.flush();
                    } finally {
                        if (outputStream != null) {
                            outputStream.close();
                        }
                    }
                    break;
                }
            }

        } finally {
            logout(ftpClient);
        }
    }

    /**
     * 登陆并且切换到远程目录
     *
     * @param ip
     * @param port
     * @param username
     * @param password
     * @param remotePath
     * @return
     * @throws IOException
     */
    private static FTPClient loginAndChangeWorkingDirectory(String ip,
                                                            int port,
                                                            String username,
                                                            String password,
                                                            String remotePath) throws IOException {
        FTPClient ftpClient = new FTPClient();

        ftpClient.connect(ip, port);
        ftpClient.login(username, password);

        if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
            ftpClient.disconnect();
        }

        ftpClient.setBufferSize(1024);//设置上传缓存大小
        ftpClient.setFileType(BINARY_FILE_TYPE);//设置文件类型

        //转移到FTP服务器目录
        ftpClient.changeWorkingDirectory(remotePath);

        return ftpClient;
    }

    /**
     * 登出
     *
     * @param ftpClient
     * @throws IOException
     */
    private static void logout(FTPClient ftpClient) throws IOException {
        if (ftpClient != null) {
            ftpClient.logout();
            if (ftpClient.isConnected()) {
                ftpClient.disconnect();
            }
        }
    }

    /**
     * ftp配置
     */
    @Data
    public static class FtpConfig {

        private String ip;
        private int port = 21;
        private String userName;
        private String password;

        private String localPath;
        private String remotePath;
        private String localName;
        private String remoteName;

        private FtpConfig(Builder builder) {
            this.ip = builder.ip;
            this.port = builder.port;
            this.userName = builder.userName;
            this.password = builder.password;

            this.localPath = builder.localPath;
            this.remotePath = builder.remotePath;
            this.localName = builder.localName;
            this.remoteName = builder.remoteName;
        }

        public static class Builder {

            String ip;
            int port = 21;
            String userName;
            String password;
            String localPath;
            String remotePath;
            String localName;
            String remoteName;

            public Builder ip(String ip) {
                this.ip = ip;
                return this;
            }

            public Builder port(int port) {
                this.port = port;
                return this;
            }

            public Builder userName(String userName) {
                this.userName = userName;
                return this;
            }

            public Builder password(String password) {
                this.password = password;
                return this;
            }

            public Builder localPath(String localPath) {
                this.localPath = localPath;
                return this;
            }

            public Builder remotePath(String remotePath) {
                this.remotePath = remotePath;
                return this;
            }

            public Builder localName(String localName) {
                this.localName = localName;
                return this;
            }

            public Builder remoteName(String remoteName) {
                this.remoteName = remoteName;
                return this;
            }

            public FtpConfig build() {
                return new FtpConfig(this);
            }

        }

    }

}
